/* 
 * MCore Extensions for TTBlue
 * Creates a wrapper for TTAudioObjects that can be used to build an audio processing graph.
 * Copyright © 2009, Timothy Place
 * 
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html 
 */

#include "multicore.h"


MCoreInlet::MCoreInlet()
: audioSources(NULL), numSources(NULL), owner(NULL), inputs(NULL), index(0)
{
//	TTAudioSignalPtr	sig = NULL;
//	TTErr				err;
//	TTUInt16			initialNumChannels = 1;
	
//	err = TTObjectInstantiate(kTTSym_audiosignal, &sig, initialNumChannels);
//	inputs->setSignal(0, sig);
}


MCoreInlet::~MCoreInlet()
{
	for(TTUInt16 i=0; i<numSources; i++){
		if(audioSources[i]->valid)
			audioSources[i]->unregisterObserverForNotifications(*owner);
	}
}


void MCoreInlet::setOwner(MCoreObjectPtr newOwner, TTAudioSignalArray* newInputs, TTUInt16 newIndex)
{
	owner = newOwner;
	inputs = newInputs;
	index = newIndex;
}


// reset
void MCoreInlet::reset()
{
	for(TTUInt16 i=0; i<numSources; i++)
		audioSources[i]->unregisterObserverForNotifications(*owner);
	
	if(audioSources && numSources)
		free(audioSources);
	audioSources = NULL;
	numSources = 0;		
}


// init the chain from which we will pull
void MCoreInlet::init()
{
	for(TTUInt16 i=0; i<numSources; i++)
		audioSources[i]->init();
}


void MCoreInlet::prepareToProcess()
{
	for(TTUInt16 i=0; i<numSources; i++)
		audioSources[i]->prepareToProcess();
}


// collect and sum the sources
void MCoreInlet::pull()
{
	TTAudioSignalPtr	pulledInput = NULL;
	TTErr				err;
	
	for(TTUInt16 i=0; i<numSources; i++){
		err = audioSources[i]->getAudioOutput(pulledInput, audioSourceOutletIndices[i]);
		if(!err)
//			(*audioInput) += (*pulledInput);
			inputs->getSignal(index) += (*pulledInput);
	}
}


// when we receive a notification than an object is going away...
void MCoreInlet::drop(TTObjectPtr theObjectBeingDeleted)
{
	TTBoolean	found = NO;
	
	for(TTUInt16 i=0; i<(numSources-1); i++){
		if(audioSources[i] == theObjectBeingDeleted)
			found = YES;
		if(found)
			audioSources[i] = audioSources[i+1];
	}
	
	audioSources[numSources-1] = 0;
	numSources--;
}


TTErr MCoreInlet::addSource(TTObjectPtr anObject, TTUInt16 sourceOutletNumber)
{
	numSources++;
	if(numSources == 1){
		audioSources = (MCoreObjectPtr*)malloc(sizeof(MCoreObjectPtr) * numSources);
		audioSourceOutletIndices = (TTUInt16*)malloc(sizeof(TTUInt16) * numSources);
	}
	else{
		audioSources = (MCoreObjectPtr*)realloc(audioSources, sizeof(MCoreObjectPtr) * numSources);
		audioSourceOutletIndices = (TTUInt16*)realloc(audioSourceOutletIndices, sizeof(TTUInt16) * numSources);
	}
	audioSources[numSources-1] = (MCoreObjectPtr)anObject;
	audioSourceOutletIndices[numSources-1] = sourceOutletNumber;
	
	// tell the source that is passed in that we want to watch it
	anObject->registerObserverForNotifications(*owner);
	
	return kTTErrNone;	
}


TTUInt16 MCoreInlet::getMaxNumSourceChannels(TTUInt16 weDeliverNumChannels)
{
	TTUInt16 sourceProducesNumChannels = 0;

	for(TTUInt16 i=0; i<numSources; i++){
//		sourceProducesNumChannels = initAudioSignal(audioInput, audioSources[i]);
		sourceProducesNumChannels = initAudioSignal(&inputs->getSignal(index), audioSources[i]);
	}
	return sourceProducesNumChannels;
}


TTUInt16 MCoreInlet::initAudioSignal(TTAudioSignalPtr aSignal, MCoreObjectPtr aSource)
{
	TTUInt16	numChannels;
	TTUInt16	sourceProducesNumChannels;
	
	numChannels = aSignal->getNumChannels();
	sourceProducesNumChannels = aSource->outputs[0].getSignal(0).getNumChannels();
	
	// currently we only up-size a signal, but perhaps we should also down-size them as appropriate?
	if(sourceProducesNumChannels > numChannels)
		aSignal->setmaxNumChannels(sourceProducesNumChannels);
	
	aSignal->setnumChannels(sourceProducesNumChannels);
	return sourceProducesNumChannels;
}
